home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Networking / ListMania1.0d1 / ListMania.c < prev    next >
Encoding:
Text File  |  1997-07-31  |  11.1 KB  |  373 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        ListMania.c
  3.  
  4.     Contains:    Sample for demonstrating use of OT list utilities.
  5.  
  6.     Written by:    Quinn "The Eskimo!"
  7.  
  8.     Copyright:    © 1997 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.     You may incorporate this sample code into your applications without
  13.     restriction, though the sample code has been provided "AS IS" and the
  14.     responsibility for its operation is 100% yours.  However, what you are
  15.     not permitted to do is to redistribute the source as "DSC Sample Code"
  16.     after having made changes. If you're going to re-distribute the source,
  17.     we require that you make it clear in the source that the code was
  18.     descended from Apple Sample Code, but that you've made changes.
  19. */
  20.  
  21. /////////////////////////////////////////////////////////////////////
  22. // The OT debugging macros in <OTDebug.h> require this variable to
  23. // be set.
  24.  
  25. #ifndef qDebug
  26. #define qDebug    1
  27. #endif
  28.  
  29. /////////////////////////////////////////////////////////////////////
  30. // Pick up all the standard OT stuff.
  31.  
  32. #include <OpenTransport.h>
  33.  
  34. /////////////////////////////////////////////////////////////////////
  35. // Pick up the OTDebugBreak and OTAssert macros.
  36.  
  37. #include <OTDebug.h>
  38.  
  39. /////////////////////////////////////////////////////////////////////
  40. // Standard C prototypes.
  41.  
  42. #include <stdio.h>
  43.  
  44. /////////////////////////////////////////////////////////////////////
  45. // OTDebugStr is not defined in any OT header files, but it is
  46. // exported by the libraries, so we define the prototype here.
  47.  
  48. extern pascal void OTDebugStr(const char* str);
  49.  
  50. /////////////////////////////////////////////////////////////////////
  51.  
  52. // Notes
  53. // -----
  54. // This sample is designed to illustrate the use of the OT link-list
  55. // routines in a simple producer/consumer environment.  The objects
  56. // being produced and consumed are widgets, as defined by the Widget
  57. // data type.  There are two key routines: ProduceWidgets and
  58. // ConsumeWidgets.  The first routine produces widgets (either by
  59. // reusing previously consumed (ie free) widgets, or by creating new
  60. // ones) and puts them on a 'pending' list.  The second consumes the
  61. // widgets by grabbing them off the pending list.  After consuming
  62. // the widget (in this sample, "consumption" means merely printing
  63. // to stdout), the routine returns the widget to a free list.
  64. //
  65. // This sample uses OTLIFO routines throughout.  OTLIFO routines
  66. // are atomic with respect to interrupts, threads, and (most probably
  67. // even MP tasks), and are faster than the standard Mac OS equivalents
  68. // (ie Enqueue/Dequeue).
  69. //
  70. // In this sample, all the code is running at SystemTask time, however
  71. // all the list management in the critical portions of the code
  72. // (ie ProduceWidgets and ConsumeWidgets) is perfectly safe to run
  73. // at interrupt time.  [ConsumeWidgets is not interrupt safe at the
  74. // moment because it uses "printf", but you can make it interrupt safe
  75. // if your definition of "consumption" is interrupt safe.]
  76. //
  77. // Another advantage of the OT list management routines is that they
  78. // support putting elements on multiple different lists simultaneously.
  79. // For example, all widgets are on the "list of all the widgets
  80. // in the system" and one of either the free list or the pending list.
  81. // OT's list management makes this very easy to do.
  82.  
  83. /////////////////////////////////////////////////////////////////////
  84.  
  85. // The Widget data structure holds all the information for a widget
  86. // object.  This includes:
  87. //
  88. // o fSequenceNumber -- A unique, monotonically increasing, sequence
  89. //   number for each widget that is ever created.
  90. // o fCreationTime -- The time at which the widget was created.
  91. // o fLastProducedTime -- The time at which the widget was last produced.
  92. //
  93. // The data structure also holds two link fields.  The first, fNext,
  94. // is used to link together all the elements on either the pending
  95. // or free widget lists.  The second link field is used to link all
  96. // of the widgets together in one long list, regardless of what their
  97. // status is.
  98.  
  99. struct Widget {
  100.     OTLink         fNext;
  101.     OTLink         fAllWidgets;
  102.     
  103.     UInt32      fSequenceNumber;
  104.     OTTimeStamp fCreationTime;
  105.     OTTimeStamp fLastProducedTime;
  106. };
  107. typedef struct Widget Widget, *WidgetPtr;
  108.  
  109. // The following three lists are used to hold lists of widgets.
  110. // gAllWidgetList is the list of all the widgets in the system.
  111. // gPendingWidgetList is the list of all the widgets that have
  112. // been produced and are awaiting consumption.  gFreeWidgetList
  113. // is the list of all the widgets that are available for reuse
  114. // by the producer.
  115. //
  116. // A widget is always on the the gAllWidgetList (through its
  117. // fAllWidgets link) and is either on the gPendingWidgetList
  118. // or the gFreeWidgetList (through its fNext link).
  119.  
  120. static OTLIFO gAllWidgetList;
  121. static OTLIFO gPendingWidgetList;
  122. static OTLIFO gFreeWidgetList;
  123.  
  124. // gLastWidgetSequenceNumber holds the sequence number of the
  125. // last widget that was produced.  When we produce a new widget,
  126. // we add one to this number to get the sequence number for the
  127. // new widget.
  128.  
  129. static UInt32 gLastWidgetSequenceNumber;
  130.  
  131. /////////////////////////////////////////////////////////////////////
  132.  
  133. static void InitWidgetLists(void)
  134.     // Initialises all of the widget lists to empty.
  135. {
  136.     gAllWidgetList.fHead = nil;
  137.     gPendingWidgetList.fHead = nil;
  138.     gFreeWidgetList.fHead = nil;
  139.     gLastWidgetSequenceNumber = 0;
  140. }
  141.  
  142. static WidgetPtr CreateWidget(void)
  143.     // This routine creates a new widget and returns it to the
  144.     // caller.  The new widget is always added to the gAllWidgetList
  145.     // through its fAllWidgets link, but is available to be linked to
  146.     // another list through its fNext link.
  147. {
  148.     WidgetPtr result;
  149.     
  150.     // Allocate the memory for the widget.
  151.     
  152.     result = OTAllocMem(sizeof(Widget));
  153.     OTAssert("CreateWidget: Could not create widget", result != nil);
  154.     
  155.     // Fill out the information fields of the widget.  Note the
  156.     // use of OTAtomicAdd32 to increment gLastWidgetSequenceNumber
  157.     // atomically.  This guarantees that the sequence number is
  158.     // unique, even if this routine is re-entered.
  159.     
  160.     OTMemzero(result, sizeof(Widget));
  161.     result->fSequenceNumber = OTAtomicAdd32(1, (long *) &gLastWidgetSequenceNumber);
  162.     OTGetTimeStamp(&result->fCreationTime);
  163.     
  164.     // Add the widget to the list of all the widgets in the system.
  165.     
  166.     OTLIFOEnqueue(&gAllWidgetList, (OTLink *) &result->fAllWidgets);
  167.     
  168.     return (result);
  169. }
  170.  
  171. static void ProduceWidgets(UInt32 howMany)
  172.     // This routine produces howMany widgets and adds them
  173.     // to the gPendingWidgetList.
  174. {
  175.     UInt32 i;
  176.     OTLink *freeLink;
  177.     WidgetPtr thisWidget;
  178.  
  179.     // Produce each new element in turn.
  180.     
  181.     for (i = 0; i < howMany; i++) {
  182.     
  183.         // Grab a free element off the front of the gFreeWidgetList.
  184.         // If that returns nil, there is no free element and we have
  185.         // to create a new widget.  Otherwise, use OTGetLinkObject
  186.         // to derive thisWidget from freeLink.
  187.     
  188.         freeLink = OTLIFODequeue(&gFreeWidgetList);
  189.         if ( freeLink != nil ) {
  190.             thisWidget = OTGetLinkObject(freeLink, Widget, fNext);
  191.         } else {
  192.             thisWidget = CreateWidget();
  193.         }
  194.         
  195.         // At this point thisWidget points to a free widget that is
  196.         // not on the gFreeWidgetList.  We now produce the widget, which in
  197.         // this sample merely involves setting fLastProducedTime.
  198.         
  199.         OTGetTimeStamp(&thisWidget->fLastProducedTime);
  200.         
  201.         // Now add the widget to the list of produced widgets.
  202.         
  203.         OTLIFOEnqueue(&gPendingWidgetList, (OTLink *) &thisWidget->fNext);
  204.     }
  205. }
  206.  
  207. static void PrintWidget(WidgetPtr thisWidget)
  208.     // Prints a widget to stdout.
  209. {
  210.     printf("  %03d, Created @ %08x%08x, Produced @ %08x%08x",
  211.         thisWidget->fSequenceNumber,
  212.         thisWidget->fCreationTime.hi, thisWidget->fCreationTime.lo,
  213.         thisWidget->fLastProducedTime.hi, thisWidget->fLastProducedTime.lo
  214.         );
  215. }
  216.  
  217. static void ConsumeWidgets(void)
  218.     // This routine consumes all of the widgets that have been produced.
  219. {
  220.     OTLink *listToConsume;
  221.     WidgetPtr thisWidget;
  222.     
  223.     // First start by atomically stealing the list of pending
  224.     // widgets.  This removes all of the widgets on gPendingWidgetList
  225.     // and returns them to us in listToConsume.  Then, reverse
  226.     // the list so that we consume them in the same order they
  227.     // were produced.
  228.     //
  229.     // Note that these two API routines are defined to deal with
  230.     // the empty list case correctly, so we don't have to
  231.     // explicitly test it ourselves.
  232.     
  233.     listToConsume = OTLIFOStealList(&gPendingWidgetList);
  234.     listToConsume = OTReverseList(listToConsume);
  235.     
  236.     while ( listToConsume != nil ) {
  237.     
  238.         // Given the link element, derive the actual widget object.
  239.         
  240.         thisWidget = OTGetLinkObject(listToConsume, Widget, fNext);
  241.         
  242.         // Now consume the widget.  In this sample, consuming
  243.         // a widget merely involves printing it to stdout.
  244.         
  245.         PrintWidget(thisWidget);
  246.         printf("\n");
  247.         
  248.         // Move along to the next list element...
  249.         
  250.         listToConsume = listToConsume->fNext;
  251.         
  252.         // ... and enqueue the most recently consumed widget on
  253.         // the list of free widgets.  Note that the order of these
  254.         // two operations is important, because thisWidget->fNext
  255.         // is the same memory location as listToConsume->fNext, so
  256.         // we can't change thisWidget->fNext (by enqueuing it)
  257.         // until we have extracted the linkage information from it.
  258.  
  259.         OTLIFOEnqueue(&gFreeWidgetList, (OTLink *) &thisWidget->fNext);
  260.     }
  261. }
  262.  
  263. static void DumpWidgetList(OTLIFO *list)
  264.     // Dump a widget list that is linked using the fNext field.
  265.     // This is appropriate for the pending and free lists of widgets.
  266. {
  267.     OTLink *link;
  268.     WidgetPtr thisWidget;
  269.     
  270.     link = list->fHead;
  271.     while ( link != nil ) {
  272.         thisWidget = OTGetLinkObject(link, Widget, fNext);
  273.         PrintWidget(thisWidget);
  274.         printf("\n");
  275.         link = link->fNext;
  276.     }
  277. }
  278.  
  279. static void DumpWidgetAllLists(void)
  280.     // Dump each af the three global lists.
  281. {
  282.     OTLink *link;
  283.     WidgetPtr thisWidget;
  284.  
  285.     printf("gPendingWidgetList\n");
  286.     DumpWidgetList(&gPendingWidgetList);
  287.  
  288.     printf("gFreeWidgetList\n");
  289.     DumpWidgetList(&gFreeWidgetList);
  290.  
  291.     printf("gAllWidgetList\n");
  292.     
  293.     link = gAllWidgetList.fHead;
  294.     while ( link != nil ) {
  295.         thisWidget = OTGetLinkObject(link, Widget, fAllWidgets);
  296.         PrintWidget(thisWidget);
  297.         printf("\n");
  298.         link = link->fNext;
  299.     }
  300. }
  301.  
  302. /////////////////////////////////////////////////////////////////////
  303.  
  304. void main(void)
  305.     // A simple command line shell for testing the various
  306.     // routines defined above.
  307. {
  308.     OSStatus err;
  309.     Boolean quitNow;
  310.     char commandString[256];
  311.     
  312.     printf("Hello Cruel World!\n");
  313.     
  314.     err = InitOpenTransport();
  315.     
  316.     if (err == noErr) {
  317.     
  318.         InitWidgetLists();
  319.     
  320.         printf("Enter a command:\n");
  321.         printf("p) Produce 3 widgets\n");
  322.         printf("P) Produce 5 widgets\n");
  323.         printf("c) Consume all pending widgets\n");
  324.         printf("d) Dump all widget lists\n");
  325.         printf("q) Quit\n");
  326.         printf("\n");
  327.         
  328.         quitNow = false;
  329.         do {
  330.             printf("Enter a command:\n");
  331.             gets(commandString);
  332.             switch( commandString[0] ) {
  333.                 case 'q':
  334.                 case 'Q':
  335.                     quitNow = true;
  336.                     break;
  337.                     
  338.                 case 'c':
  339.                 case 'C':
  340.                     ConsumeWidgets();
  341.                     break;
  342.                     
  343.                 case 'p':
  344.                     ProduceWidgets(3);
  345.                     break;
  346.                 case 'P':
  347.                     ProduceWidgets(5);
  348.                     break;
  349.                     
  350.                 case 'd':
  351.                 case 'D':
  352.                     DumpWidgetAllLists();
  353.                     break;
  354.                     
  355.                 default:
  356.                     printf("Don't understand “%s”.");
  357.                     break;
  358.             }
  359.         } while ( ! quitNow );
  360.         
  361.         CloseOpenTransport();
  362.     }
  363.     
  364.     if (err == noErr) {
  365.         printf("Success.\n");
  366.     } else {
  367.         printf("Failed with error %d.\n", err);
  368.     }
  369.     printf("Done.  Press command-Q to Quit.\n");
  370. }
  371.  
  372.  
  373.